/*
 * All header file for c language MUST be include : in extern "C" { }
 */
extern "C" {
#include "../src/uni_event_route.c"
}

int count;
int error;
int success;

/*
 * H2UNIT is a unit test Suite, which contains several test cases.
 */
H2UNIT(event_route) {
  /*
   * setup() will be executed before every test case belong to this suite.
   * Typically it is used to prepare preconditions.
   */
  void setup() {
    count = 0;
    error = 0;
    success = 0;
  }

  /*
   * teardown() will be executed after every test case belong to this suite.
   * whatever test case passed or failed.
   * Typically it is used to release resource.
   */
  void teardown() {
  }
};

#define EVENT_TYPE_1 0
#define EVENT_TYPE_2 1
#define EVENT_TYPE_3 20
#define EVENT_TYPE_4 127
#define EVENT_TYPE_5 MAX_ALLOWED_EVENT_TYPE
#define EVENT_TYPE_6 (MAX_ALLOWED_EVENT_TYPE + 1)

int good_event_handler_1(Event *event) {
  count += 1;
  success += 1;
  return 0;
}

int good_event_handler_2(Event *event) {
  count += 1;
  success += 1;
  return 0;
}

int bad_event_handler(Event *event) {
  count += 1;
  error += 1;
  return -1;
}

H2CASE(event_route, "register") {
  int ret;
  EventReceiver *receiver;
  uni_s32 events[6] = {EVENT_TYPE_1,
                       EVENT_TYPE_2,
                       EVENT_TYPE_3,
                       EVENT_TYPE_4,
                       EVENT_TYPE_5,
                       EVENT_TYPE_6
  };
  ret = EventRouteRegister(good_event_handler_1, 6, events);
  H2EQ_TRUE(0 == ret);
  receiver = list_entry(g_event_receivers.next, EventReceiver,
                        link);
  H2EQ_MATH((void*)good_event_handler_1, (void*)receiver->handler);
  ret = BitMapTest(receiver->event_set, EVENT_TYPE_1);
  H2EQ_MATH(0, ret);
  ret = BitMapTest(receiver->event_set, EVENT_TYPE_2);
  H2EQ_MATH(0, ret);
  ret = BitMapTest(receiver->event_set, EVENT_TYPE_3);
  H2EQ_MATH(0, ret);
  ret = BitMapTest(receiver->event_set, EVENT_TYPE_4);
  H2EQ_MATH(0, ret);
  ret = BitMapTest(receiver->event_set, EVENT_TYPE_5);
  H2EQ_MATH(0, ret);
  ret = BitMapTest(receiver->event_set, EVENT_TYPE_6);
  H2EQ_MATH(-1, ret);
  /*
   * The same handler shouldn't be registered twice.
   */
  ret = EventRouteRegister(good_event_handler_1, 1, events);
  H2EQ_TRUE(-1 == ret);
  /*
   * Null shouln't be registered.
   */
  ret = EventRouteRegister(NULL, 0, NULL);
  H2EQ_TRUE(-1 == ret);
}

H2CASE(event_route, "unregister") {
  int ret;
  uni_s32 events[6] = {EVENT_TYPE_1,
                       EVENT_TYPE_2,
                       EVENT_TYPE_3,
                       EVENT_TYPE_4,
                       EVENT_TYPE_5,
                       EVENT_TYPE_6
  };
  EventRouteRegister(good_event_handler_1, 1, events);
  ret = EventRouteUnregister(good_event_handler_1);
  H2EQ_TRUE(0 == ret);
  H2EQ_TRUE(list_empty(&g_event_receivers));
  ret = EventRouteUnregister(good_event_handler_2);
  H2EQ_TRUE(0 == ret);
  ret = EventRouteUnregister(NULL);
  H2EQ_TRUE(0 == ret);
}

/*
 * testcase to test EventRouteProcess function.
 * include normal and abnormal conditionis.
 */
H2CASE(event_route, "event process") {
  int ret;
  uni_s32 events[6] = {EVENT_TYPE_1,
                       EVENT_TYPE_2,
                       EVENT_TYPE_3,
                       EVENT_TYPE_4,
                       EVENT_TYPE_5,
                       EVENT_TYPE_6
  };
  Event *event = EventCreate(0, EVENT_TYPE_1, NULL, NULL);
  ret = EventRouteRegister(bad_event_handler, 1, events);
  H2EQ_TRUE(0 == ret);

  /*
   * The fail handler should return false when the event is passed to it to handle;
   */
  ret = EventRouteProcess(event);
  H2EQ_TRUE(-1 == ret);
  H2EQ_TRUE(1 == count);
  H2EQ_TRUE(1 == error);
  H2EQ_TRUE(0 == success);

  ret = EventRouteRegister(good_event_handler_2, 2, events);
  H2EQ_TRUE(0 == ret);

  /*
   * normal and fail handler should both process the event.
   */
  ret = EventRouteProcessAll(event);
  H2EQ_TRUE(-1 == ret);
  H2EQ_TRUE(3 == count);
  H2EQ_TRUE(2 == error);
  H2EQ_TRUE(1 == success);
  EventFree(event);

  /*
   * change event to specific event only handled by  normal handler.
   * only normal handler should process it.
   */
  event = EventCreate(0, EVENT_TYPE_2, NULL, NULL);
  ret = EventRouteProcessAll(event);
  H2EQ_TRUE(0 == ret);
  H2EQ_TRUE(4 == count);
  H2EQ_TRUE(2 == error);
  H2EQ_TRUE(2 == success);
  EventFree(event);

  /*
   * change event to a event which is not registed by any handler.
   * it should not be handled by any handler
   */
  event = EventCreate(0, EVENT_TYPE_5, NULL, NULL);
  ret = EventRouteProcessAll(event);
  H2EQ_TRUE(0 == ret);
  H2EQ_TRUE(4 == count);
  H2EQ_TRUE(2 == error);
  H2EQ_TRUE(2 == success);
  EventFree(event);

  EventRouteUnregister(bad_event_handler);
  EventRouteUnregister(good_event_handler_2);
  EventRouteUnregister(good_event_handler_1);
}


